//
//	SysImg.c	
//	
//	Written by J Brown 8/3/2003	Freeware
//
//

#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(lib, "comctl32.lib")

// Save icon resources to disk - defined in SaveIcon.c
BOOL SaveIcon(TCHAR *szIconFile, HICON hIcon[], int nNumIcons);

HWND hwndMain;
HWND hwndList;

HMODULE		hShell32;

HIMAGELIST	hLarge;
HIMAGELIST	hSmall;

TCHAR szAppName[] = _T("System ImageList Viewer");

//
//	Typedefs for SHELL APIs
//
typedef BOOL (WINAPI * SHGIL_PROC)	(HIMAGELIST *phLarge, HIMAGELIST *phSmall);
typedef BOOL (WINAPI * FII_PROC)	(BOOL fFullInit);

//
//	Use undocumented SHELL APIs to get system imagelists
//
BOOL GetSystemImageList(HIMAGELIST *phLarge, HIMAGELIST *phSmall)
{
	SHGIL_PROC	Shell_GetImageLists;
	FII_PROC	FileIconInit;

	if(phLarge == 0 || phSmall == 0)
		return FALSE;

	// Don't free until we terminate - otherwise, the image-lists will be destroyed
	if(hShell32 == 0)
		hShell32 = LoadLibrary("shell32.dll");

	if(hShell32 == 0)
		return FALSE;

	// Get Undocumented APIs from Shell32.dll: 
	// Shell_GetImageLists and FileIconInit
	//
	Shell_GetImageLists  = (SHGIL_PROC)  GetProcAddress(hShell32, (LPCSTR)71);
	FileIconInit		 = (FII_PROC)    GetProcAddress(hShell32, (LPCSTR)660);

	// FreeIconList@8 = ord 227

	if(Shell_GetImageLists == 0)
	{
		FreeLibrary(hShell32);
		return FALSE;
	}

	// Initialize imagelist for this process - function not present on win95/98
	if(FileIconInit != 0)
		FileIconInit(TRUE);

	// Get handles to the large+small system image lists!
	Shell_GetImageLists(phLarge, phSmall);

	return TRUE;
}

//
//
//
void FreeSystemImageList()
{
	FreeLibrary(hShell32);
	hShell32 = 0;
}

//
//	Update the listview with al system icons
//
BOOL FillList(HWND hwnd)
{
	LVITEM lvitem;
	char ach[20];
	int i, count;

	// Clear the list before we start
	ListView_DeleteAllItems(hwnd);

	ListView_SetImageList(hwnd, hLarge, LVSIL_NORMAL);
	ListView_SetImageList(hwnd, hSmall, LVSIL_SMALL);

	// Get number of icons in system image list
	count = ImageList_GetImageCount(hLarge);

	// add to list
	for(i = 0; i < count; i++)
	{
		wsprintf(ach, "%d", i);

		lvitem.mask			= LVIF_IMAGE | LVIF_TEXT;
		lvitem.iItem		= i;
		lvitem.iSubItem		= 0;
		lvitem.pszText		= ach;
		lvitem.iImage		= i;
		
		ListView_InsertItem(hwnd, &lvitem);
	}

	return TRUE;
}

//
//	Display the standard SaveAs dialog
//
BOOL SaveIconDlg(HWND hwndParent, TCHAR szFileName[], int nFileNameLen)
{
	OPENFILENAME ofn;
	static char szFilter[] = "Icon Files (*.ico)\0*.ico\0\0";

	// clear out the structure
	ZeroMemory(&ofn, sizeof(ofn));

	// nul-terminate filename
	szFileName[0] = '\0';

	ofn.lpstrTitle		= _T("Save Icon");
	ofn.lStructSize		= sizeof(ofn);
	ofn.hInstance		= GetModuleHandle(0);
	ofn.hwndOwner		= hwndParent;
	ofn.Flags			= OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING;
	ofn.lpstrFilter		= szFilter;
	ofn.nFilterIndex	= 1;
	ofn.nMaxFile		= nFileNameLen;
	ofn.lpstrFile		= szFileName;

	return GetSaveFileName(&ofn);
}

//
//	Save the currently selected icon to disk
//
BOOL SaveSelectedIcon(HWND hwndList)
{
	LVITEM		lvitem;
	HICON		hIcon[2];
	int			idx;
	TCHAR		szFileName[MAX_PATH];

	// get current selection
	idx = ListView_GetSelectionMark(hwndList);

	if(idx == -1)
		return FALSE;

	lvitem.iItem		= idx;
	lvitem.iSubItem		= 0;
	lvitem.mask			= LVIF_IMAGE;

	// Get the selected item's image index
	ListView_GetItem(hwndList, &lvitem);

	// Make array of icons to save
	hIcon[1] = ImageList_GetIcon(hLarge, lvitem.iImage, ILD_NORMAL);
	hIcon[0] = ImageList_GetIcon(hSmall, lvitem.iImage, ILD_NORMAL);

	// Use Save-common-dialog to get filename from user
	if(SaveIconDlg(hwndMain, szFileName, MAX_PATH))
	{
		// Save large+small icons into same icon resource
		return SaveIcon(szFileName, hIcon, 2);
	}
	else
	{
		return FALSE;
	}
}

//
//	(Very) simple function to copy to clipboard. Seems to work :)
//
BOOL CopyIconToClipboard(HICON hIcon)
{
	ICONINFO iconInfo;

	GetIconInfo(hIcon, &iconInfo);

	OpenClipboard(hwndMain);
	
	EmptyClipboard();

	SetClipboardData(CF_BITMAP, iconInfo.hbmColor);

	CloseClipboard();

	return TRUE;
}

BOOL CopySelectedIcon(HWND hwndList)
{
	LVITEM		lvitem;
	HICON		hIcon;
	int			idx;
	DWORD		dwStyle;

	idx = ListView_GetSelectionMark(hwndList);

	if(idx == -1)
		return FALSE;

	lvitem.iItem		= idx;
	lvitem.iSubItem		= 0;
	lvitem.mask			= LVIF_IMAGE;

	// Get the selected item's image index
	ListView_GetItem(hwndList, &lvitem);

	// Make array of icons to save
	// get the viewmode (large/small icons
	dwStyle = GetWindowLong(hwndList, GWL_STYLE);

	if((dwStyle & LVS_TYPEMASK) == LVS_ICON)
		hIcon = ImageList_GetIcon(hLarge, lvitem.iImage, ILD_NORMAL);
	else
		hIcon = ImageList_GetIcon(hSmall, lvitem.iImage, ILD_NORMAL);
		
	// Copy :)
	return CopyIconToClipboard(hIcon);
}

//
//	Main window procedure
//
LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	DWORD		dwStyle;
	NMLISTVIEW	*nmlv;

	switch(msg)
	{
	case WM_CREATE:

		dwStyle = WS_CHILD;

		// If Windows 95, do not destroy imagelists when listview is destroyed
		if(GetVersion() & 0x80000000)
			dwStyle |= LVS_SHAREIMAGELISTS;

		hwndList = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
			dwStyle, 0, 0, 600, 0, hwnd, 0, GetModuleHandle(0), 0);

		FillList(hwndList);

		ShowWindow(hwndList, SW_SHOW);

		//SendMessage(hwnd, WM_SETICON, LoadIcon(0, IDI_APPLICATION), 0);

		return 0;

	case WM_SIZE:
		MoveWindow(hwndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_CLOSE:
		DestroyWindow(hwnd);
		return 0;

	case WM_DESTROY:
		DestroyWindow(hwndList);
		PostQuitMessage(0);
		return 0;

	case WM_SETFOCUS:
		SetFocus(hwndList);
		return 0;

	case WM_NOTIFY:
		
		nmlv = (NMLISTVIEW *)lParam;
		
		// if a listview item has changed
		if(nmlv->hdr.code == LVN_ITEMCHANGED)
		{
			// look out for selection change
			if(nmlv->uNewState & LVIS_SELECTED)
			{
				// enable menu "save" item
				EnableMenuItem(GetMenu(hwnd), IDM_FILE_SAVE, MF_BYCOMMAND | MF_ENABLED);
				EnableMenuItem(GetMenu(hwnd), IDM_FILE_COPY, MF_BYCOMMAND | MF_ENABLED);
			}
			else
			{
				// disable menu "save" item
				EnableMenuItem(GetMenu(hwnd), IDM_FILE_SAVE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
				EnableMenuItem(GetMenu(hwnd), IDM_FILE_COPY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
			}
			return 0;
		}

		return 0;

	case WM_COMMAND:

		switch(LOWORD(wParam))
		{
		// Show about box
		case IDM_FILE_ABOUT:
			MessageBox(hwnd, 
				"SysImg - System ImageList Viewer\r\n\r\n"
				"Written by J Brown\r\nFreeware\r\n\r\n"
				"Homepage at http://www.catch22.uk.net\t", 
				szAppName, MB_OK|MB_ICONINFORMATION);

			return 0;

		// Save currently selected ICON
		case IDM_FILE_SAVE:
			SaveSelectedIcon(hwndList);
			return 0;

		// Copy ICON bitmap to clipboard
		case IDM_FILE_COPY:
			CopySelectedIcon(hwndList);
			return 0;

		// Quit :)
		case IDM_FILE_EXIT:
			PostMessage(hwnd, WM_CLOSE, 0, 0);
			return 0;

		// Update the main view
		case IDM_VIEW_REFRESH:
			FillList(hwndList);
			return 0;

		// View large (standard) icons
		case IDM_VIEW_LARGE:
			
			dwStyle = GetWindowLong(hwndList, GWL_STYLE);
			SetWindowLong(hwndList, GWL_STYLE, dwStyle & ~LVS_TYPEMASK | LVS_ICON);

			ListView_SetIconSpacing(hwndList, -1, -1);
			
			CheckMenuItem(GetMenu(hwnd), IDM_VIEW_LARGE, MF_CHECKED   | MF_BYCOMMAND);
			CheckMenuItem(GetMenu(hwnd), IDM_VIEW_SMALL, MF_UNCHECKED | MF_BYCOMMAND);
			return 0;

		// View small icons
		case IDM_VIEW_SMALL:
			
			dwStyle = GetWindowLong(hwndList, GWL_STYLE);
			SetWindowLong(hwndList, GWL_STYLE, dwStyle & ~LVS_TYPEMASK | LVS_SMALLICON);
			
			ListView_SetIconSpacing(hwndList, -1, -1);

			CheckMenuItem(GetMenu(hwnd), IDM_VIEW_LARGE, MF_UNCHECKED | MF_BYCOMMAND);
			CheckMenuItem(GetMenu(hwnd), IDM_VIEW_SMALL, MF_CHECKED   | MF_BYCOMMAND);

			return 0;


		}

	case WM_SETTINGCHANGE:
		// need to call FileIconInit(TRUE) in case the icon cache is reinitialized
		break;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}

ATOM InitMainWnd()
{
	WNDCLASSEX wc;

	wc.cbSize			= sizeof(wc);
	wc.style			= 0;
	wc.lpfnWndProc		= WndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= GetModuleHandle(0);
	wc.hIcon			= LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
	wc.hCursor			= LoadCursor (NULL, IDC_ARROW);
	wc.hbrBackground	= 0;
	wc.lpszMenuName		= MAKEINTRESOURCE(IDR_MENU1);
	wc.lpszClassName	= szAppName;
	wc.hIconSm			= LoadIcon (NULL, IDI_APPLICATION);

	return RegisterClassEx(&wc);
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int iShowCmd)
{
	MSG		msg;
	HACCEL	hAccelTable;			

	INITCOMMONCONTROLSEX icex;

	// Register main window class
	InitMainWnd();

	//	Initialize common controls library
	icex.dwSize  = sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC   = ICC_COOL_CLASSES|ICC_BAR_CLASSES|ICC_LISTVIEW_CLASSES;
	
	InitCommonControlsEx(&icex);		//necessary for toolbar, status etc

	// Retrieve the system image lists
	if(!GetSystemImageList(&hLarge, &hSmall))
		return FALSE;

	//
	//	Create main window
	//
	hwndMain = CreateWindowEx(0,
				szAppName,				// window class name
				szAppName,				// window caption
				WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
				CW_USEDEFAULT,			// initial x position
				CW_USEDEFAULT,			// initial y position
				560,					// initial x size
				320,					// initial y size
				NULL,					// parent window handle
				NULL,					// use window class menu
				hInst,					// program instance handle
				NULL);					// creation parameters

	ShowWindow(hwndMain, iShowCmd);

	//Initialise the keyboard accelerators
	hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1));

	//
	//	Standard message loop
	//
	while(GetMessage(&msg, NULL,0,0))
	{
		if(!TranslateAccelerator(hwndMain, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	FreeSystemImageList();

	return 0;
}